#pragma once

#include <windows.h>
#include <list>

#include <boost/thread/tss.hpp>
#include <boost/thread/mutex.hpp>


#include "XString.h"
#include "Exception.h"



namespace platform {

	
template<typename T>
class Tls
{
public:
	struct tls_info_t {
		Tls<T> *pthis;
		T *pobj;

		tls_info_t(Tls<T> *pt) : pthis(pt), pobj(NULL) {}
	};
	typedef void (*cleanup_func_t)(T*);

	/**
	 * returns info structure for current thread,
	 * if called for the first time - will create
	 * a new one with "NULL" object
	 */
	inline tls_info_t & getThreadInfo(void) const {
		tls_info_t * pinfo = m_tls.get();
		if (pinfo == NULL) {
			pinfo = new tls_info_t(const_cast<Tls<T>*>(this));
			m_tls.reset(pinfo);
		}
		return *pinfo;
	}

public:
	Tls(void) : m_cleanup_func(NULL), m_tls(ThreadCleanup) {}
	Tls(cleanup_func_t cfunc) : m_cleanup_func(cfunc), m_tls(ThreadCleanup) {}

	inline T * get(void) const {
		return getThreadInfo().pobj;
	}

	inline void set(T *pt) {
		getThreadInfo().pobj = pt;
		boost::mutex::scoped_lock lock(m_mutex);
		m_objects.push_back(pt);
	}

	/**
	 * This function iterates over all live instancec of
	 * of T for all threads.
	 * FUNCTOR will be invoked with (T*) for each element,
	 * so it can be any callable type: function, functor
	 */
	template<typename FUNCTOR>
	FUNCTOR for_each(FUNCTOR func) {
		boost::mutex::scoped_lock lock(m_mutex);
		list_objects_t::iterator itEnd = m_objects.end();
		for (list_objects_t::iterator it = m_objects.begin(); it != itEnd; ++it)
			func(*it);
		return func;
	}

	virtual ~Tls(void);

private:
	static void ThreadCleanup(tls_info_t *pinfo);
	void threadCleanup(T *pobj);

private:
	cleanup_func_t m_cleanup_func;

	// NOTE: this definition must come before "m_tls",
	// as we want the list to be live when destructing
	// "m_tls" - it calls "threadCleanup"
	typedef std::list<T*> list_objects_t;
	list_objects_t m_objects;

	boost::mutex m_mutex;
	mutable boost::thread_specific_ptr<tls_info_t> m_tls;

};



template<typename T>
Tls<T>::~Tls(void)
{
}

template<typename T>
void Tls<T>::ThreadCleanup(tls_info_t *pinfo) {
	if (pinfo == NULL) return;
	pinfo->pthis->threadCleanup(pinfo->pobj);
	delete pinfo;
}

template<typename T>
void Tls<T>::threadCleanup(T *pobj) {
	if (pobj == NULL)
		return;

	boost::mutex::scoped_lock lock(m_mutex);
	for (list_objects_t::iterator it = m_objects.begin(); it != m_objects.end(); ++it)
		if (*it == pobj) {
			m_objects.erase(it);
			break;
		}
	lock.unlock();

	if (m_cleanup_func != NULL)
		m_cleanup_func(pobj);
}


}  // end namespace
